CRM Deals
Bulk "import into pipeline": upsert contacts and create one deal per row. Throttled generously so a chunked multi-batch import can complete.
POST
/
crm
/
deals
/
bulk-import
Bulk "import into pipeline": upsert contacts and create one deal per row.
Throttled generously so a chunked multi-batch import can complete.
curl --request POST \
--url https://api.example.com/crm/deals/bulk-import \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"rows": [
{
"firstName": "<string>",
"lastName": "<string>",
"email": "jsmith@example.com",
"phoneNumber": "<string>",
"tags": [
"<string>"
],
"notes": "<string>",
"accountOwnerEmail": "jsmith@example.com",
"meetingTypeRef": "<string>",
"crmCompanyRef": "<string>",
"additionalData": {},
"dealName": "<string>",
"dealValue": 1,
"dealCurrency": "<string>",
"dealExpectedCloseDate": "<string>",
"dealOwnerEmail": "jsmith@example.com",
"dealNotes": "<string>"
}
],
"pipelineId": "<string>",
"stageId": "<string>",
"updateExisting": true
}
'import requests
url = "https://api.example.com/crm/deals/bulk-import"
payload = {
"rows": [
{
"firstName": "<string>",
"lastName": "<string>",
"email": "jsmith@example.com",
"phoneNumber": "<string>",
"tags": ["<string>"],
"notes": "<string>",
"accountOwnerEmail": "jsmith@example.com",
"meetingTypeRef": "<string>",
"crmCompanyRef": "<string>",
"additionalData": {},
"dealName": "<string>",
"dealValue": 1,
"dealCurrency": "<string>",
"dealExpectedCloseDate": "<string>",
"dealOwnerEmail": "jsmith@example.com",
"dealNotes": "<string>"
}
],
"pipelineId": "<string>",
"stageId": "<string>",
"updateExisting": True
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
rows: [
{
firstName: '<string>',
lastName: '<string>',
email: 'jsmith@example.com',
phoneNumber: '<string>',
tags: ['<string>'],
notes: '<string>',
accountOwnerEmail: 'jsmith@example.com',
meetingTypeRef: '<string>',
crmCompanyRef: '<string>',
additionalData: {},
dealName: '<string>',
dealValue: 1,
dealCurrency: '<string>',
dealExpectedCloseDate: '<string>',
dealOwnerEmail: 'jsmith@example.com',
dealNotes: '<string>'
}
],
pipelineId: '<string>',
stageId: '<string>',
updateExisting: true
})
};
fetch('https://api.example.com/crm/deals/bulk-import', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/crm/deals/bulk-import",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'rows' => [
[
'firstName' => '<string>',
'lastName' => '<string>',
'email' => 'jsmith@example.com',
'phoneNumber' => '<string>',
'tags' => [
'<string>'
],
'notes' => '<string>',
'accountOwnerEmail' => 'jsmith@example.com',
'meetingTypeRef' => '<string>',
'crmCompanyRef' => '<string>',
'additionalData' => [
],
'dealName' => '<string>',
'dealValue' => 1,
'dealCurrency' => '<string>',
'dealExpectedCloseDate' => '<string>',
'dealOwnerEmail' => 'jsmith@example.com',
'dealNotes' => '<string>'
]
],
'pipelineId' => '<string>',
'stageId' => '<string>',
'updateExisting' => true
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/crm/deals/bulk-import"
payload := strings.NewReader("{\n \"rows\": [\n {\n \"firstName\": \"<string>\",\n \"lastName\": \"<string>\",\n \"email\": \"jsmith@example.com\",\n \"phoneNumber\": \"<string>\",\n \"tags\": [\n \"<string>\"\n ],\n \"notes\": \"<string>\",\n \"accountOwnerEmail\": \"jsmith@example.com\",\n \"meetingTypeRef\": \"<string>\",\n \"crmCompanyRef\": \"<string>\",\n \"additionalData\": {},\n \"dealName\": \"<string>\",\n \"dealValue\": 1,\n \"dealCurrency\": \"<string>\",\n \"dealExpectedCloseDate\": \"<string>\",\n \"dealOwnerEmail\": \"jsmith@example.com\",\n \"dealNotes\": \"<string>\"\n }\n ],\n \"pipelineId\": \"<string>\",\n \"stageId\": \"<string>\",\n \"updateExisting\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/crm/deals/bulk-import")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"rows\": [\n {\n \"firstName\": \"<string>\",\n \"lastName\": \"<string>\",\n \"email\": \"jsmith@example.com\",\n \"phoneNumber\": \"<string>\",\n \"tags\": [\n \"<string>\"\n ],\n \"notes\": \"<string>\",\n \"accountOwnerEmail\": \"jsmith@example.com\",\n \"meetingTypeRef\": \"<string>\",\n \"crmCompanyRef\": \"<string>\",\n \"additionalData\": {},\n \"dealName\": \"<string>\",\n \"dealValue\": 1,\n \"dealCurrency\": \"<string>\",\n \"dealExpectedCloseDate\": \"<string>\",\n \"dealOwnerEmail\": \"jsmith@example.com\",\n \"dealNotes\": \"<string>\"\n }\n ],\n \"pipelineId\": \"<string>\",\n \"stageId\": \"<string>\",\n \"updateExisting\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/crm/deals/bulk-import")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"rows\": [\n {\n \"firstName\": \"<string>\",\n \"lastName\": \"<string>\",\n \"email\": \"jsmith@example.com\",\n \"phoneNumber\": \"<string>\",\n \"tags\": [\n \"<string>\"\n ],\n \"notes\": \"<string>\",\n \"accountOwnerEmail\": \"jsmith@example.com\",\n \"meetingTypeRef\": \"<string>\",\n \"crmCompanyRef\": \"<string>\",\n \"additionalData\": {},\n \"dealName\": \"<string>\",\n \"dealValue\": 1,\n \"dealCurrency\": \"<string>\",\n \"dealExpectedCloseDate\": \"<string>\",\n \"dealOwnerEmail\": \"jsmith@example.com\",\n \"dealNotes\": \"<string>\"\n }\n ],\n \"pipelineId\": \"<string>\",\n \"stageId\": \"<string>\",\n \"updateExisting\": true\n}"
response = http.request(request)
puts response.read_body{
"contactsCreated": 123,
"contactsUpdated": 123,
"contactsSkipped": 123,
"dealsCreated": 123,
"dealsSkipped": 123,
"failed": 123,
"issues": [
{}
]
}{
"statusCode": 400,
"message": [
"limit must not be greater than 100"
],
"error": "BadRequestException"
}{
"statusCode": 400,
"message": [
"limit must not be greater than 100"
],
"error": "BadRequestException"
}{
"statusCode": 400,
"message": [
"limit must not be greater than 100"
],
"error": "BadRequestException"
}{
"statusCode": 400,
"message": [
"limit must not be greater than 100"
],
"error": "BadRequestException"
}Authorizations
ApiKeyJWTApiUserHeader
Bearer token: a Platform API Key (format: ak_live::) or a Personal Access Token (format: rgo-...). PATs always act as the token owner.
Body
application/json
Maximum array length:
500Show child attributes
Show child attributes
When true, contacts whose email already exists are updated in place. A deal is created for every row regardless, matching how Pipedrive/HubSpot import deals (contacts dedupe by email, deals are never deduplicated).
Response
Newly inserted contacts.
Existing contacts updated in place (only when updateExisting is true).
Existing contacts left untouched (a deal is still created for them).
Deals created in the target pipeline stage.
Deals not created because the plan deal limit was reached.
Rows that hit a technical error (contact or deal).
⌘I
Bulk "import into pipeline": upsert contacts and create one deal per row.
Throttled generously so a chunked multi-batch import can complete.
curl --request POST \
--url https://api.example.com/crm/deals/bulk-import \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"rows": [
{
"firstName": "<string>",
"lastName": "<string>",
"email": "jsmith@example.com",
"phoneNumber": "<string>",
"tags": [
"<string>"
],
"notes": "<string>",
"accountOwnerEmail": "jsmith@example.com",
"meetingTypeRef": "<string>",
"crmCompanyRef": "<string>",
"additionalData": {},
"dealName": "<string>",
"dealValue": 1,
"dealCurrency": "<string>",
"dealExpectedCloseDate": "<string>",
"dealOwnerEmail": "jsmith@example.com",
"dealNotes": "<string>"
}
],
"pipelineId": "<string>",
"stageId": "<string>",
"updateExisting": true
}
'import requests
url = "https://api.example.com/crm/deals/bulk-import"
payload = {
"rows": [
{
"firstName": "<string>",
"lastName": "<string>",
"email": "jsmith@example.com",
"phoneNumber": "<string>",
"tags": ["<string>"],
"notes": "<string>",
"accountOwnerEmail": "jsmith@example.com",
"meetingTypeRef": "<string>",
"crmCompanyRef": "<string>",
"additionalData": {},
"dealName": "<string>",
"dealValue": 1,
"dealCurrency": "<string>",
"dealExpectedCloseDate": "<string>",
"dealOwnerEmail": "jsmith@example.com",
"dealNotes": "<string>"
}
],
"pipelineId": "<string>",
"stageId": "<string>",
"updateExisting": True
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
rows: [
{
firstName: '<string>',
lastName: '<string>',
email: 'jsmith@example.com',
phoneNumber: '<string>',
tags: ['<string>'],
notes: '<string>',
accountOwnerEmail: 'jsmith@example.com',
meetingTypeRef: '<string>',
crmCompanyRef: '<string>',
additionalData: {},
dealName: '<string>',
dealValue: 1,
dealCurrency: '<string>',
dealExpectedCloseDate: '<string>',
dealOwnerEmail: 'jsmith@example.com',
dealNotes: '<string>'
}
],
pipelineId: '<string>',
stageId: '<string>',
updateExisting: true
})
};
fetch('https://api.example.com/crm/deals/bulk-import', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/crm/deals/bulk-import",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'rows' => [
[
'firstName' => '<string>',
'lastName' => '<string>',
'email' => 'jsmith@example.com',
'phoneNumber' => '<string>',
'tags' => [
'<string>'
],
'notes' => '<string>',
'accountOwnerEmail' => 'jsmith@example.com',
'meetingTypeRef' => '<string>',
'crmCompanyRef' => '<string>',
'additionalData' => [
],
'dealName' => '<string>',
'dealValue' => 1,
'dealCurrency' => '<string>',
'dealExpectedCloseDate' => '<string>',
'dealOwnerEmail' => 'jsmith@example.com',
'dealNotes' => '<string>'
]
],
'pipelineId' => '<string>',
'stageId' => '<string>',
'updateExisting' => true
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/crm/deals/bulk-import"
payload := strings.NewReader("{\n \"rows\": [\n {\n \"firstName\": \"<string>\",\n \"lastName\": \"<string>\",\n \"email\": \"jsmith@example.com\",\n \"phoneNumber\": \"<string>\",\n \"tags\": [\n \"<string>\"\n ],\n \"notes\": \"<string>\",\n \"accountOwnerEmail\": \"jsmith@example.com\",\n \"meetingTypeRef\": \"<string>\",\n \"crmCompanyRef\": \"<string>\",\n \"additionalData\": {},\n \"dealName\": \"<string>\",\n \"dealValue\": 1,\n \"dealCurrency\": \"<string>\",\n \"dealExpectedCloseDate\": \"<string>\",\n \"dealOwnerEmail\": \"jsmith@example.com\",\n \"dealNotes\": \"<string>\"\n }\n ],\n \"pipelineId\": \"<string>\",\n \"stageId\": \"<string>\",\n \"updateExisting\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/crm/deals/bulk-import")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"rows\": [\n {\n \"firstName\": \"<string>\",\n \"lastName\": \"<string>\",\n \"email\": \"jsmith@example.com\",\n \"phoneNumber\": \"<string>\",\n \"tags\": [\n \"<string>\"\n ],\n \"notes\": \"<string>\",\n \"accountOwnerEmail\": \"jsmith@example.com\",\n \"meetingTypeRef\": \"<string>\",\n \"crmCompanyRef\": \"<string>\",\n \"additionalData\": {},\n \"dealName\": \"<string>\",\n \"dealValue\": 1,\n \"dealCurrency\": \"<string>\",\n \"dealExpectedCloseDate\": \"<string>\",\n \"dealOwnerEmail\": \"jsmith@example.com\",\n \"dealNotes\": \"<string>\"\n }\n ],\n \"pipelineId\": \"<string>\",\n \"stageId\": \"<string>\",\n \"updateExisting\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/crm/deals/bulk-import")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"rows\": [\n {\n \"firstName\": \"<string>\",\n \"lastName\": \"<string>\",\n \"email\": \"jsmith@example.com\",\n \"phoneNumber\": \"<string>\",\n \"tags\": [\n \"<string>\"\n ],\n \"notes\": \"<string>\",\n \"accountOwnerEmail\": \"jsmith@example.com\",\n \"meetingTypeRef\": \"<string>\",\n \"crmCompanyRef\": \"<string>\",\n \"additionalData\": {},\n \"dealName\": \"<string>\",\n \"dealValue\": 1,\n \"dealCurrency\": \"<string>\",\n \"dealExpectedCloseDate\": \"<string>\",\n \"dealOwnerEmail\": \"jsmith@example.com\",\n \"dealNotes\": \"<string>\"\n }\n ],\n \"pipelineId\": \"<string>\",\n \"stageId\": \"<string>\",\n \"updateExisting\": true\n}"
response = http.request(request)
puts response.read_body{
"contactsCreated": 123,
"contactsUpdated": 123,
"contactsSkipped": 123,
"dealsCreated": 123,
"dealsSkipped": 123,
"failed": 123,
"issues": [
{}
]
}{
"statusCode": 400,
"message": [
"limit must not be greater than 100"
],
"error": "BadRequestException"
}{
"statusCode": 400,
"message": [
"limit must not be greater than 100"
],
"error": "BadRequestException"
}{
"statusCode": 400,
"message": [
"limit must not be greater than 100"
],
"error": "BadRequestException"
}{
"statusCode": 400,
"message": [
"limit must not be greater than 100"
],
"error": "BadRequestException"
}